/*
 *  Copyright (c) 2014 ZengYajian
 *
 *  Simple httpServer, wirtten by c.
 *  by ZengYajian
 */

#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "log.h"
#include "iolib.h"
#include "http.h"
#include "helper.h"
#include "filter.h"

#define _BUFSIZE (1024*8)

void web(int fd);

int main(int argc, char **argv)
{
	int hit, pid, port, listenfd, socketfd;
	socklen_t length;
	static struct sockaddr_in client_addr;
	static struct sockaddr_in server_addr;

	if (argc<3 || argc >3 || !strcmp(argv[1], "-?")) {
		printf("%s", usage);
		exit(0);
	}

	port = atoi(argv[1]);
	if (port < 0 || port > 60000) {
		printf("unknow listen port '%d'\n", port);
		exit(0);
	}

	/* change to the web directory */
	if (chdir(argv[2]) == -1) {
		printf("ERROR: Can't change to the web directory '%s'\n", argv[2]);
		exit(4);
	}

	/* become deamon */
	if (fork() != 0)
		return 0;

	signal(SIGCLD, SIG_IGN); /* ignore child death */
	signal(SIGHUP, SIG_IGN); /* ignore terminal hangups */

	log_init(DEBUG, "miniHttpServer", "./");
	_log(DEBUG, "miniHttpServer starting ...\n");

	/* setup the network socket */
	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	if (listenfd < 0) {
		_log(ERROR, "system call 'socket'\n");
		_log(ERROR, "exit...\n");
		exit(1);
	}

	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	server_addr.sin_port = htons(port);
	if (bind(listenfd, (struct sockaddr *)&server_addr, sizeof(server_addr))<0) {
		_log(ERROR, "system call 'bind'\n");
		_log(ERROR, "exit...\n");
		exit(1);
	}

	if (listen(listenfd, 64) < 0) {
		_log(ERROR, "system call 'listen'\n");
		_log(ERROR, "exit...\n");
		exit(1);
	}

	for(hit=0; hit<100; hit++) {
		length = sizeof(client_addr);
		socketfd = accept(listenfd, (struct sockaddr *)&client_addr, &length);
		if (socketfd < 0) {
			_log(ERROR, "system call 'accept'\n");
		}

		fprintf(stderr, "\nlistenfd: %x\nsocketfd: %x\n", listenfd, socketfd);
		pid = fork();
		if (pid < 0) {
			_log(ERROR, "system call 'fork'\n");
		} else {
			if (pid == 0) {
				close(listenfd);
				web(socketfd);
			} else {
				close(socketfd);
			}
		}
	}

	return 0;
}

void web(int fd)
{
	static char buffer[_BUFSIZE];
	int size;
	struct http_request_t *p;
	struct io_handler *h;
	char path[256], filetype[32];

	size = read(fd, buffer, _BUFSIZE);
	printf("fd '%x'\n", fd);
	printf("contan:\n%s\n", buffer);

	p = http_request_alloc(REQUEST_GET);
	http_content_parse(buffer, size, p);
	resource_remap(p->res, path, filetype);
	printf("Request type: %s, path: %s\n", filetype, path);

	memset(buffer, 0, _BUFSIZE);
	h = io_file_init(path, O_RDONLY);
	if (!h) {
		fprintf(stderr, "Opend file '%s' error\n", path);
		goto err_out;
	}

	// respon
	sprintf(buffer, "HTTP/1.1 200 OK\nServer: miniHttpServer/%d.0\nContent-Length: %ld\nConnection: close\nContent-Type: %s\n\n",
		1, h->file_size, filetype);
	write(fd, buffer, strlen(buffer));

	while ((size = io_file_read(h, buffer, _BUFSIZE)) > 0)
		write(fd, buffer, size);

	io_file_destroy(h);
err_out:
	http_request_free(p);
	close(fd);
	exit(1);
}
